package dbms.check;

import java.util.Map;

import dbms.absyn.*;
import dbms.server.DbmsServer;
import dbms.symbol.Symbol;

public class CheckResult {
	
	public static ExpList result;
	String ntable;
	java.io.PrintStream out;
	
	public CheckResult (ExpList res) {
		result = res;
	}

	public void CheckExpList (ExpList res) {
		CheckExp(result.exp);
		if (result.next != null) CheckExpList(result.next);
	}

	private void CheckExp(Exp exp) {
		if (exp instanceof SelectExp) CheckSelectExp((SelectExp) exp);
		if (exp instanceof InsertExp) CheckInsertExp((InsertExp) exp);
		if (exp instanceof UpdateExp) CheckUpdateExp((UpdateExp) exp);
		if (exp instanceof DeleteExp) CheckDeleteExp((DeleteExp) exp);
		if (exp instanceof JoinExp) CheckJoinExp((JoinExp) exp);/*
		if (exp instanceof CreateDbClause) CheckCreateDbClause((CreateDbClause) exp);
		if (exp instanceof CreateTabClause) CheckCreateTabClause((CreateTabClause) exp);*/
		if (exp instanceof UnionExp) CheckUnionExp((UnionExp) exp);
		if (exp instanceof UnionAllExp) CheckUnionAllExp((UnionAllExp) exp);
		if (exp instanceof AlterExp) CheckAlterExp((AlterExp) exp);/*
		if (exp instanceof CheckExp) CheckCheckExp((CheckExp) exp);*/
		if (exp instanceof IndexExp) CheckIndexExp((IndexExp) exp);
		if (exp instanceof DropExp) CheckDropClause(((DropExp) exp).drop_stmt);
		if (exp instanceof ViewExp) CheckViewExp((ViewExp) exp);
	}

	private void CheckUpdateExp(UpdateExp exp) {
		SetClause ss = exp.set_stmt;
		WhereClause ws = exp.where_stmt;
		ntable = exp.update_stmt.table.name;
		new CheckTable(ntable).check();
		CheckSetList(ss.set_list);
		CheckWhereClause(ws, ntable);
	}

	private void CheckSetList(SetList set_list) {
		CheckSet(set_list.set);
		CheckSetList(set_list.next);
	}

	private void CheckSet(Set set) {
		new CheckType(set.attr.attr.name, ntable, set.value).check();
	}

	private void CheckDropClause(DropClause exp) {
		//drop table
		if (exp instanceof DropTabClause) new CheckTable(((DropTabClause) exp).table.name);
		//drop database
		//truncate table
		if (exp instanceof TruncateClause) new CheckTable(((TruncateClause) exp).table.name);
		//drop view
	}

	private void CheckIndexExp(IndexExp exp) {
		//
	}

	private void CheckViewExp(ViewExp exp) {
		//
	}

	private void CheckAlterExp(AlterExp exp) {
		//check table name
		ntable = exp.alter_stmt.table.name;
		//check constraint
	}

	private void CheckUnionAllExp(UnionAllExp exp) {
		//two table
	}

	private void CheckUnionExp(UnionExp exp) {
		//two table
	}

	private void CheckJoinExp(JoinExp exp) {
		FromClause fs = exp.from_stmt;
		ntable = fs.tableList.attr.attr.name;  //FIXME
		CheckFromClause(fs);
		JoinClause js = exp.join_stmt;
		if (js instanceof InnerJoinClause) CheckInnerJoinClause((InnerJoinClause) js);
		if (js instanceof LeftJoinClause) CheckLeftJoinClause((LeftJoinClause) js);
		if (js instanceof RightJoinClause) CheckRightJoinClause((RightJoinClause) js);
		if (js instanceof FullJoinClause) CheckFullJoinClause((FullJoinClause) js);
		SelectClause ss = exp.select_stmt;
		CheckSelectClause(ss, ntable);
	}

	private void CheckFullJoinClause(FullJoinClause js) {
		//check table name
		ntable = js.table.name;
		new CheckTable(ntable).check();
		//check on_clause
		CheckOnClause(js.on_clause);
	}

	private void CheckRightJoinClause(RightJoinClause js) {
		//check table name
		ntable = js.table.name;
		new CheckTable(ntable).check();
		//check on_clause
		CheckOnClause(js.on_clause);
	}

	private void CheckLeftJoinClause(LeftJoinClause js) {
		//check table name
		ntable = js.table.name;
		new CheckTable(ntable).check();
		//check on_clause
		CheckOnClause(js.on_clause);
	}

	private void CheckInnerJoinClause(InnerJoinClause js) {
		//check table name
		ntable = js.table.name;
		new CheckTable(ntable).check();
		//check on_clause
		CheckOnClause(js.on_clause);
	}

	private void CheckOnClause(OnClause on_clause) {
		//two table
	}

	private void CheckDeleteExp(DeleteExp exp) {
		//check delete clause
		DeleteClause ds = exp.delete_stmt;
		ntable = ds.table.name;
		new CheckTable(ntable).check();
		//check where clause
		WhereClause ws = exp.where_stmt;
		CheckWhereClause(ws, ntable);
	}

	private void CheckInsertExp(InsertExp exp) {
		CheckInsertClause(exp.insert_stmt);
		CheckValueClause(exp.value_stmt, exp.insert_stmt.table.name);
		CheckConstraint(exp);
	}

	private void CheckConstraint(InsertExp exp) {
		InsertClause is = exp.insert_stmt;
		AttrList al = null;
		AttrList temp = al;
		if (is.attr_list != null) al = is.attr_list;
		else {
			ntable = is.table.name;
			Map<String, Integer> field = DbmsServer.masterPage.tableMap.get(ntable).table.getTableSchema().getFieldRank();
			for (String attr : field.keySet()) {
				Symbol symbol = new Symbol(attr);
				temp.attr = new Attribute(symbol.name);
				temp = temp.next; 
			}
			temp = null;
		}
		ValueClause vs = exp.value_stmt;
	}

	private void CheckValueClause(ValueClause value_stmt, String table) {
		ValueList vl = value_stmt.value_list;
		CheckValueList(vl, table);
	}

	private void CheckValueList(ValueList vl, String table) {
		
	}

	private void CheckInsertClause(InsertClause insert_stmt) {
		ntable = insert_stmt.table.name;
		new CheckTable(ntable).check();
		AttrList al = insert_stmt.attr_list;
		if (al != null) CheckAttrList(al, ntable);
	}

	private void CheckSelectExp(SelectExp exp) {
		SelectClause ss = exp.select_stmt;
		FromClause fs = exp.from_stmt;
		WhereClause ws = exp.where_stmt;
		OrderClause os = exp.order_stmt;
		
		CheckFromClause(fs);
		String ntable = fs.tableList.attr.attr.name;
		
		CheckSelectClause(ss, ntable);
		CheckWhereClause(ws, ntable);
		if (os != null) CheckOrderClause(os, ntable);
	}

	private void CheckOrderClause(OrderClause os, String ntable) {
		new CheckAttr(os.attr.attr.name, ntable).check();
	}

	private void CheckWhereClause(WhereClause ws, String ntable) {
		ConditionList cl = ws.condition_list;
		CheckConditionList(cl, ntable);
	}

	private void CheckConditionList(ConditionList cl, String ntable) {
		if (cl.condition == null) CheckConditionList(cl, ntable);
		if (cl.next != null) {
			CheckCondition(cl.condition, ntable);
			CheckConditionList(cl.next, ntable);
		}
		else CheckCondition(cl.condition, ntable);
	}

	private void CheckCondition(Condition c, String ntable) {
		String attr = c.attr.attr.name;
		if (c.condition != null) CheckCondition(c.condition, ntable);
		new CheckAttr(attr, ntable).check();
		if (c.value != null) new CheckType(attr, ntable, c.value).check();
		if (c.value_left != null) new CheckType(attr, ntable, c.value_left).check();
		if (c.value_right != null) new CheckType(attr, ntable, c.value_right).check();
		if (c.value_list != null) CheckValueList(attr, c.value_list, ntable);		
	}

	private void CheckValueList(String attr, ValueList vl, String ntable) {
		new CheckType(attr, ntable, vl.value).check();
		if (vl.next != null) CheckValueList(attr, vl.next, ntable);
	}

	private void CheckSelectClause(SelectClause ss, String ntable) {
		AttrList al = ss.attr_list;
		AliasList aal = ss.attr_as_list;
		if (al != null) CheckAttrList(al, ntable);
		if (aal != null) CheckAttrAsList(aal, ntable);
		int i = ss.number;
		String s = ss.str;
		if (i != 0) {
			if (s == "PERCENT") {
				if ((i <= 0) || (i > 100)) out.println("ERROR: Invalid Percentage.");
			}
			else new CheckTopAttr(ss.number, ss.attr_list.attr.attr.name, ntable).check();
		}
	}

	private void CheckAttrAsList(AliasList aal, String ntable) {
		new CheckAttr(aal.attr.attr.name, ntable).check();
		if (aal.next != null) CheckAttrAsList(aal.next, ntable);
	}

	private void CheckAttrList(AttrList al, String ntable) {
		// check attr of the AttrList, ntable is the name of table
		new CheckAttr(al.attr.attr.name, ntable).check();
		if (al.next != null) CheckAttrList(al.next, ntable);
	}

	private void CheckFromClause(FromClause fs) {
		//check the name of table in the from_stmt
		ntable = fs.tableList.attr.attr.name;  //FIXME
		new CheckTable(ntable).check();
		
		//check the alias_list int the from_stmt
		AttrList al = fs.tableList;
		while (al != null) {
			new CheckTable(al.attr.attr.name).check();
			al = al.next;
		}
	}
}